"""" 
Copyright 2009 Texas A&M University
 
Licensed under the Apache License, Version 2.0 (the "License"); you may not use 
this file except in compliance with the License. You may obtain a copy of the 
License at

http://www.apache.org/licenses/LICENSE-2.0
  
Unless required by applicable law or agreed to in writing, software distributed 
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY KIND, either express or implied. See the License for the 
specific language governing permissions and limitations under the License.
"""
from re import compile
from copy import copy
from os.path import join, dirname
from logging import getLogger
from sys import modules

from zope.interface import implements

from lxml import etree

from twisted.python import log 

from meercat.base.metadata import Metadata
from meercat.interfaces import IMetadata
from meercat.mapreduce.interfaces import IMapper
from meercat.mapreduce.exceptions import *
from meercat.mapreduce.mappers.base import BaseMapper



log = getLogger('meercat.mapreduce.mappers.xsl')

class PackageResolver(etree.Resolver):
    expression = compile('^(?P<package>[\d\w\-_]+(\.[\d\w\-]+)*):(?P<path>.*)$')
    
    def resolve(self, system_url, public_id, context):
        match = self.expression.match(system_url)
        if not match:
            return None
        
        try:
            __import__(match.group('package'))
        except ImportError:
            return None
        
        return self.resolve_filename(join(dirname(modules[match.group('package')].__file__),
                                          match.group('path')), context)

class XslMapper(BaseMapper):
    implements(IMapper)
    
    def __init__(self, *formats):
        """Factory for the XslMapper
        
        @type  transforms: list
        @param transforms: A list or other iterable of tuples. Each tuple should
          contain 3 elements: source_format, destination_format, and stylesheet.
          The stylesheet should be parseable by etree.parse
        """
        self._formats = formats
        self._loadStylesheets()
    
    def _loadStylesheets(self):
        self._stylesheets = {}
        for format in self._formats:
            try:
                t = (format[0],format[1],)
                parser = etree.XMLParser()
                parser.resolvers.add(PackageResolver())
                
                self._stylesheets[t] = etree.XSLT(etree.parse(format[2], parser))
            except Exception, e:
                raise MapperError(u'Error loading a stylesheet: %s' % (str(e),))
    
    def __getstate__(self):
        return self._formats
    
    def __setstate__(self, formats):
        self._formats = formats
        self._loadStylesheets()
    
    def getFormats(self):
        return self._stylesheets.keys()
    
    def post_transform(self, metadata, element):
        pass
    
    def map(self, metadata):
        self._validate(metadata)
        output_format = self.getOutputFormat(metadata.getFormat())
        stylesheet = self._stylesheets[(metadata.getFormat(),
                                        output_format,)]
                
        output = stylesheet(etree.fromstring(metadata.getValue()))
        self.post_transform(metadata, output)
        
        return Metadata(format=self.getOutputFormat(metadata.getFormat()),
                        source=metadata.getSource(),
                        value=etree.tostring(output, encoding='utf-8'),
                        instance=metadata.getInstance())
